package karaokit.com;


import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Iterator;
import java.util.TreeMap;

/**
 * this class represents an entire Lyrics object. It parses the given .lrc file
 * and later on give access to any LyricLine in given a wanted time stamp.
 * The supported lyrics files are of the type:
 * [mm:ss]Lyrics-text
 * or
 * [mm:ss.SS]Lyrics-text
 */
public class Lyrics {
	

	public static DateFormat LyricsFormatter = new SimpleDateFormat("mm:ss");	
	static String TimePattern1 = "\\d{1,2}:\\d{1,2}"; //[mm:ss]
	static String TimePattern2 = "\\d{1,2}:\\d{1,2}.\\d{3}"; //[mm:ss.SS]
	
	/**
	 * this inner class represents a time frame - with a start and end points.
	 */
	class LyricsTime implements Comparable<LyricsTime> {		
		private int _start, _end; // in milliseconds
		public LyricsTime(int start, int end) {
			this._start = start;
			this._end = end;
		}
		public int getStart() {
			return _start;
		}
		public void setStart(int _start) {
			this._start = _start;
		}
		public int getEnd() {
			return _end;
		}
		public void setEnd(int _end) {
			this._end = _end;
		}
		
		/**
		 * a standard compareTo() implementation that treats any time frame 
		 * that is contained inside this time frame as equal to this object.
		 */
		public int compareTo(LyricsTime time) {
			if (this._start >= time.getStart()) {
				if (this._end <= time._end)
					return 0;
				return 1;
			}
			else if (this._end >= time.getEnd()) 
				return 0;			
			return -1;
		}	
	}
	
	/*
	 * An array of the lines of the lyric file
	 */
	private  TreeMap<LyricsTime, String> _lyrics;
	
	public Lyrics(File lyricFile) {
		_lyrics = new TreeMap<LyricsTime, String>();
		parseLyrics(lyricFile);		
	}
	
	/**
	 * this method parses the given lyrics file
	 * note that each line can be fully analyzed only once we got 
	 * to its following - because only then we can know what is 
	 * the end of its time frame.
	 */
	private void parseLyrics(File lyricFile) {
		int startTime = 0;
		String lyrics = "";
		try {
			BufferedReader read  = new BufferedReader(new FileReader(lyricFile));
			String line, timeStamp;			

			while ((line = read.readLine()) != null) {				
				if (line.equals("") || !line.contains("[") || !line.contains("]"))
					continue;
				timeStamp = line.substring(line.indexOf("[")+1, line.indexOf("]"));
				if (!timeStamp.matches(TimePattern1) && !timeStamp.matches(TimePattern2))
					continue;				

				int endTime = toMillis(timeStamp); 
				if (endTime != 0) {
					_lyrics.put(new LyricsTime(startTime,endTime), lyrics);
				}
				startTime = endTime; // for the next iteration
				lyrics = (line.endsWith("]")) ?
						"" : line.substring(line.indexOf("]")+1);				
			}
			//deal with the last lyrics line:
			_lyrics.put(new LyricsTime(startTime, Integer.MAX_VALUE), lyrics);
			read.close();			
		} catch (Exception e) {
			System.err.println(e.getMessage());
			e.printStackTrace();			
		}
	}


	/** 
	 * @param t - the time requested
	 * @return the lyrics itself
	 */
	public String getLine(int t){		
		return _lyrics.get(new LyricsTime(t,t)); // return the lyrics that contains [t,t] time frame. 
	}
	
	/**
	 * this method converts the time stamp of the given file into milliseconds
	 */
	public static int toMillis(String time){
		if (time.contains(".")) {
			return (Integer.parseInt(time.substring(0, time.indexOf(":")))*60*1000) +
			(Integer.parseInt(time.substring(time.indexOf(":")+1, time.indexOf(".")))*1000 + 
			(Integer.parseInt(time.substring(time.indexOf(".")+1))));
		}
		return (Integer.parseInt(time.substring(0, time.indexOf(":")))*60*1000) +
			(Integer.parseInt(time.substring(time.indexOf(":")+1)))*1000;
	}
	
	/**
	 * this method prints all the lyrics line (mainly for possible debugging)
	 */
	public void printAll() {			
		Iterator<LyricsTime> iter = _lyrics.keySet().iterator();
		while (iter.hasNext()) {
			LyricsTime t = iter.next();
			String lyrics = _lyrics.get(t);
			System.out.println("[" + t.getStart() + "-" + t.getEnd() + "] " + lyrics); 		
		}
	}
}
